<?php
###############   COPYLEFT GPLv3 LICENSE   ###############
##
## JFX Version 0.2.9
## Website Management Software
## www.jfxcms.com
##
## Copyright 2009 GPLv3 - http://www.opensource.org/licenses/gpl-3.0.html
##
## Anthony Gallon
## oi_antz@hotmail.com
##
## Permission is hereby granted to any person having a copy of this software
## to freely use and modify as required so long as the copyright notices
## and branding remain intact.
##
## Full license details available at http://www.jfxcms.com/license
##
###############   COPYLEFT GPLv3 LICENSE   ###############

class JFX_Block {

	/**
	 * Children of this block
	 * @var JFX_Block
	 */
    public $elements = array();
	/**
	 * Database table jfx_blocks
	 * @var array
	 */
    public $details = array(
        'id' => '',
        'parent_id' => '',
        'module_key' => '',
        'module_action' => '',
        'sorting' => '',
        'page_parent' => '',
        'class_name' => '',
        'ajax_enabled' => '',
        'is_droppable' => '',
        'page_id' => '',
		'workspace_id' => '',
        'exec_order' => '',
        'template' => '',
        'template_id' => '',
        'block_style' => '',
        'php_code' => '',
        'is_template' => 0,
        'template_script' => '',
        'template_style' => ''
    );
    public $id = '';
    public $parentid = '';
    public $pageid = '';
    public $workspaceid = '';
    public $moduleKey = '';
    public $moduleAction = '';
    public $object = NULL;
    public $title = 'New Block';
    public $defaultContent = '';
	public $isPage = false;
	public $isBlock = true;
	public $isTemplate = false;
    
	/**
	 * Config data
	 * @var JFX_Block_Config
	 */
	public $config = array();

    public $saved = false;

    public function __construct($blockId=null, $pageid=''){
        if($blockId !== null && $blockId!=''){
			$this->loadById($blockId, $pageid);
		}
    }

	public static function getBlockById($id, $pageId, $workspaceid = '', $recursive = true, $loadObject = true){
		$REGISTRY = JFX::registry('JFX_Block_Registry');
		$SETTINGS = JFX::registry('JFX_Settings');
		$CONFIG = JFX::registry('config');

		if($pageId==''){
			$pageId = $id;
		}

		$registryKey = 'JFX_Block_'.$id.'_'.$pageId.'_'.$workspaceid;
		if(!$REGISTRY->isRegistered($registryKey)){

			if(!array_key_exists($registryKey, $GLOBALS)){
				$GLOBALS[$registryKey] = true;
			}else{
				throw new exception('trying to decode '.$id.' for '.$pageId.' a second time');
			}

			if(is_numeric($id)){
				// its a page
				$block = new JFX_Page;
				$block->loadById($id, $pageId, $workspaceid, $recursive, $loadObject);
				$block->set('id', 'jfxpage-'.$pageId);

			}else if(self::isTemplate($id)){
				// its a template
				$block = new JFX_Template;
				$block->loadById($id, $pageId, $workspaceid, $recursive, $loadObject);
			}else{
				// its a block
				$block = new JFX_Block;
				$block->loadById($id, $pageId, $workspaceid, $recursive, $loadObject);
				
			}
			
			if($block->details['id']==''){
				
				if(is_numeric(substr($id, 8))){
					// try for page block
					$block = new JFX_Page;
					$block->loadById(substr($id, 8), $pageId, $workspaceid, $recursive, $loadObject);
					$block->set('id', 'jfxpage-'.$pageId);
				}else{
					// try for template block
					$block = new JFX_Block;
					$block->loadById($id, $pageId, $workspaceid, $recursive, $loadObject);
				}
			}
			if(!is_object($block) || (!($block instanceof JFX_Block) && !($block instanceof JFX_Page))){
				throw new Exception('Cannot load block by id: '.$id);
			}

			$REGISTRY->register($registryKey, $block);
		}
		return $REGISTRY->registry($registryKey);
	}

	public static function getTitleById($id, $pageId='', $language='', $workspace=''){

		$block = self::getBlockById($id, $pageId, $workspace);
		$SETTINGS = JFX::registry('JFX_Settings');
		$CORE = JFX::registry('JFX_Core');

		if($workspace==''){
			$workspace = $SETTINGS->get('live_workspace_id');
		}

		if((array_key_exists('template_id', $block->details) && strlen($block->details['template_id'])>0)){
			return self::getTitleById($block->details['template_id'], $pageId);
		}

		return $CORE->getContentLang('heading', $id, $language, $workspace);
	}

    public function setClassName($className){
	    if(is_array($className)){
		    $className = implode(' ', $className);
	    }
        $this->details['class_name'] = $className;

        if(is_object($this->object) && method_exists($this->object, 'setClassName'))
            $this->object->setClassName($className, $this->details);
    }

	public function addClassName($className){
		$allClassnames = explode(' ', $this->details['class_name']);
		if(!in_array($className, $allClassnames)){
			$this->details['class_name'] = $this->details['class_name'].' '.$className;
		}
	}

    public function getClassName(){
	    if(!array_key_exists('class_name', $this->details)){
		    return '';
	    }
        $className = $this->details['class_name'];
        if(is_object($this->object) && method_exists($this->object, 'getClassName'))
            $className .= $this->object->getClassName($this->details);

        return $className;
    }

    public function setTemplate($template){
        if(is_object($this->object) && method_exists($this->object, 'setTemplate'))
            $template = $this->object->setTemplate($template, $this->details);
        $this->details['template'] = $template;
    }

    public function getTemplate(){
        return $this->details['template'];
    }

    public function setStyle($style){
        $this->details['block_style'] = $style;
    }

	public static function generateBlockId($pageid, $module, $workspace=''){
		$DB = JFX::registry('db');
		$CONFIG = JFX::registry('config');
		$USER = JFX::registry('JFX_User');
		if($workspace==''){
			$workspace = $USER->workspace;
		}
		$countStart = 0;
		$idPattern = 'jfxpage-'.$pageid.'-'.$module.'-';
		$newId = $idPattern.$countStart;
		while($DB->countRows($CONFIG->dbprefix.'blocks', "id = '{$newId}'")>0){
			$countStart++;
			$newId = $idPattern.$countStart;
		}

		return $newId;
	}

    public function delete(){

		if(!$this->canDelete()){
			return false;
		}

        $DB = JFX::registry('db');
        $CONFIG = JFX::registry('config');
        $LANG = JFX::registry('lang');
		$CORE = JFX::registry('JFX_Core');

        foreach($this->elements as $k=>$v){
            $v->delete();
        };
        $id = explode('-', $this->id);
        $pageid = $id[1];
        $moduleKey = $id[2];
        $instanceid = $id[3];
        $params = array(
            'page_id' => $this->pageid,
            'workspace_id' => $this->workspaceid,
            'instance_id' => $instanceid
        );
        if(!is_object($this->object)) $this->loadObject();
        $this->object->delete($this->details);
        $DB->delete($CONFIG->dbprefix.'blocks', "id = '{$this->id}' AND workspace_id = '{$this->workspaceid}'");
        $CORE->deleteContentLang('heading', $this->id, '*', $this->workspaceid);
    }

    public function clearCache(){
        $CACHE = JFX::registry('JFX_Block_Cache');
        $CACHE->clear($this->id.'_'.$this->workspaceid);
    }

    public function loadObject(){
        if($this->moduleKey == '') $this->moduleKey = 'content';
        if(!is_object($this->object)) $this->object = JFX::registry('JFX_Module_'.ucfirst(strtolower($this->moduleKey)));
        $this->object->setBlockId($this->id);
        return $this->object;
    }

    public function loadById($id, $pageId='', $workspaceid = '', $recursive = true, $loadObject = true){
        
        $JFXMemDebug[] = array('bytes'=>memory_get_usage(), 'file'=>__FILE__, 'line'=>__LINE__, 'time' => getmicrotime(), 'desc' => 'Before load by id '.$id);

        $DB = JFX::registry('db');
        $LANG = JFX::registry('lang');
        $USER = JFX::registry('JFX_User');
        $CONFIG = JFX::registry('config');
		$REGISTRY = JFX::registry('JFX_Block_Registry');
		$CORE = JFX::registry('JFX_Core');
		$SETTINGS= JFX::registry('JFX_Settings');

		$this->config = new JFX_Block_Config($id);

		$templatePageid = $SETTINGS->get('template_page_id');
		
		$substrId = substr($id, 8);
		if($pageId==$id || is_numeric($substrId)){
			// its a page
			if(!is_numeric($id)){
				$id = substr($id, 8);
			}
		}

		if($pageId==''){
			$pageId = $SETTINGS->get('template_page_id');
		}

		$registryKey = 'JFX_Block_'.$id.'_'.$pageId.'_'.$workspaceid.'_'.intval($recursive).'_'.intval($loadObject);

		if(false && $REGISTRY->isRegistered($registryKey)){
			
			return $REGISTRY->registry($registryKey);
		}else{
			if($workspaceid == '') $workspaceid = $USER->workspace;
			$liveWorkspaceid = $SETTINGS->get('live_workspace_id');
			
			$pageQuery = '';
			$table = 'blocks';
			
			if($this->isPage){
				$table = 'pages';
			}else{
				if($pageId!=''){
					$pageQuery = " AND (page_id = '{$pageId}' OR page_id = '{$templatePageid}') ";
				}
			}

			$id = $DB->escape($id);
			$q = "SELECT * FROM {$CONFIG->dbprefix}{$table} WHERE id = '{$id}' {$pageQuery} AND (workspace_id = '{$workspaceid}' OR workspace_id = '{$liveWorkspaceid}')";
			$details = $DB->fetchRow($q);

			if(!is_array($details) || count($details)==0){
				return false;
			}
			$this->setDetails($details);
			$this->pageid = $pageId;

			$this->saved = true;
			if(!$this->isPage && $loadObject){
				$this->loadObject();
				$this->defaultContent = $this->object->getDefaultContent($this->moduleAction);
			}

			$this->title = $CORE->getContentLang('heading', $this->id, '', $this->workspaceid);

			if($recursive){
				$els = array();

				$parentId = $id;
				if($this->isPage){
					$parentId = 'jfxpage-'.$id;
				}

				$pageWhere = " AND page_id = '{$pageId}' ";
				if($templatePageid != $pageId){
					$pageWhere = " AND (page_id = '{$pageId}' OR page_id = '{$templatePageid}') ";
				}
				$q = "SELECT * FROM {$CONFIG->dbprefix}blocks WHERE parent_id = '{$parentId}'
					AND (workspace_id = '{$workspaceid}' OR workspace_id = '{$liveWorkspaceid}') {$pageWhere} ORDER BY
					sorting ASC";


				$tmpEls = $DB->fetchAll($q);
				if(!is_array($tmpEls)) $tmpEls = array();

				foreach($tmpEls as $k=>$v){
					if($this->getDetails('is_template') >0){
						$el = new JFX_Template;
					}else{
						$el = new JFX_Block;
					}
					$el->loadById($v['id'], $pageId, $workspaceid, $recursive, $loadObject);
					$els[] = $el;
				}



				if(!$this->isPage && strlen($this->getDetails('template_id'))>0){
					if(strlen($this->getDetails('template_id'))>0){
						$tmpBlock = JFX_Block::getBlockById($this->getDetails('template_id'), $pageId, $liveWorkspaceid, $recursive, $loadObject);
					}
					foreach($tmpBlock->elements as $el){
						$newDetails = array(
							'page_id'=>$pageId
						);
						$el->setDetails($newDetails);
						$els[] = $el;
					}

				}

				$this->elements = $els;
			}else{
				$this->elements = array();
			}

			$hookParams = array('block'=>&$this);
			JFX::hook('JFX_Core.getBlockById', $hookParams);

			$JFXMemDebug[] = array('bytes'=>memory_get_usage(), 'file'=>__FILE__, 'line'=>__LINE__, 'time' => getmicrotime(), 'desc' => 'After load by id '.$id);

			$REGISTRY->register($registryKey, $this);

			return true;

		}

    }

	public function hasConfig($keyname){
		return $this->config->has($keyname);
	}

	public function setConfig($keyname, $parm){
		return $this->config->set($keyname, $parm);
	}

	public function getConfig($keyname){
		return $this->config->get($keyname);
		if(in_array($keyname, $this->config)){
			return $this->config[$keyname];
		}else if(in_array($keyname, $this->details)){
			return $this->details[$keyname];
		}
	}

	public function __call($methodname, $parms){
		return $this->getConfig($methodname);
	}

	public static function isTemplate($blockId){
        $DB = JFX::registry('db');
        $CONFIG = JFX::registry('config');
		$SETTINGS = JFX::registry('JFX_Settings');
		if(substr($blockId, 0, 9)=='jfxpage-'.$SETTINGS->get('template_page_id')){
			return true;
		}
	}

    public function prepare(){
        $SMARTY = JFX::registry('Smarty');

        $JFXMemDebug[] = array('bytes'=>memory_get_usage(), 'file'=>__FILE__, 'line'=>__LINE__, 'time' => getmicrotime(), 'desc' => 'Before prepare '.$this->id);


        $REG = JFX::registry('JFX_Block_Registry');
        $CACHE = JFX::registry('JFX_Block_Cache');

        $VIEW = JFX::registry('JFX_View');
        $SMARTY = JFX::registry('Smarty');
        $DB = JFX::registry('db');
        $CONFIG = JFX::registry('config');
        $USER = JFX::registry('JFX_User');
        $CRYPT = JFX::registry('JFX_Crypt');
        $LINK = JFX::registry('JFX_Link');
        $THEME = JFX::registry('JFX_Theme');
        $CORE = JFX::registry('JFX_Core');
        $SETTINGS = JFX::registry('JFX_Settings');


        if(false && $CACHE->isCached($this->id.'_'.$this->workspaceid)){
            $content = $CACHE->get($this->id.'_'.$this->workspaceid);
        }else{
            if(!is_object($this->object)) $this->loadObject();
            $tempid = $this->id;
            if(trim($this->details['template_id'])!=''){
                // its a template being mirrored
                $this->details['id'] = $this->details['template_id'];
                $content = $this->object->prepare($this->details);
            }else{
                // not a template being mirrored
                $content = $this->object->prepare($this->details);
            }

			$hookParams = array(
				'content' => &$content,
				'block' => &$this
			);

			JFX::hook('JFX_Block.prepareContent', $hookParams);
            
            if(strstr($this->details['template'], ':|content|:')!==false) $content = str_replace(':|content|:', $content, $this->details['template']);

            if($this->object->useCache($this->details)) $CACHE->set($this->id.'_'.$this->workspaceid, $content);
        }

        $content = JFX::fetchSmarty($content);

        $REG->register('render_'.$this->id, $content);


        $JFXMemDebug[] = array('bytes'=>memory_get_usage(), 'file'=>__FILE__, 'line'=>__LINE__, 'time' => getmicrotime(), 'desc' => 'After prepare '.$this->id);


    }

    public function render(){

        global $JFXMemDebug;

        $JFXMemDebug[] = array('bytes'=>memory_get_usage(), 'file'=>__FILE__, 'line'=>__LINE__, 'time' => getmicrotime(), 'desc' => 'Before render '.$this->id);


        $REG = JFX::registry('JFX_Block_Registry');
		
		if(!$REG->isRegistered('render_'.$this->id)){
            if(!is_object($this->object)) $this->loadObject();
            $this->prepare();
        }

		$hookParams = array('block'=>$this);
		JFX::hook('JFX_Block.renderPre', $hookParams);

        $output = '
'/*<!-- start #'.$this->id.'-->*/.'
<div id="'.$this->id.'" class="'.$this->getClassName().'" style="'.$this->details['block_style'].'">
';
        
        $output .= '    '.$REG->registry('render_'.$this->id).'
    ';
        
        foreach($this->elements as $k=>$v){
            $output .= '
'.$v->render().'
        ';
        }

        $output .= '
</div>
'/*<!-- end #'.$this->id.'-->*/.'

';

        $JFXMemDebug[] = array('bytes'=>memory_get_usage(), 'file'=>__FILE__, 'line'=>__LINE__, 'time' => getmicrotime(), 'desc' => 'After render '.$this->id);


        return $output;
    }

    public static function newModuleBlock($moduleKey, $moduleAction, $workspaceid=''){
        $DB = JFX::registry('db');
        $CONFIG = JFX::registry('config');
        if(!JFX_Module::isValidModule($moduleKey)) return false;
		if($workspaceid==''){
			$USER = JFX::registry('JFX_User');
			$workspaceid = $USER->workspace;
		}
        $block = new JFX_Block;
		$block->workspaceid = $workspaceid;
        $block->moduleKey = $moduleKey;
        $block->moduleAction = $moduleAction;
		$block->setDetails(array('workspace_id' => $workspaceid));
        $block->loadObject();
		
        $block->details = array_merge($block->details, $block->object->getDefaultDetails($moduleAction));
		$block->setTitle($block->object->getDefaultContent($moduleAction));

		$block->details = $block->details;
        return $block;
    }

    public function getDetails($keyname=''){
		
        $details = $this->details;
		if($keyname!=''){
			if(array_key_exists($keyname, $details)){
				return $details[$keyname];
			}
		}

		$this->loadObject();
        $details['default_content'] = $this->defaultContent;
		$details['workspace_id'] = $this->workspaceid;
		if(!$this->isPage){
			$details['content'] = $this->object->getContentRaw($details);
		}else{
			$details['page_id'] = $this->pageid;
		}
        $details['title'] = $this->title;

		return $details;
		
    }

    public function save(){
        $DB = JFX::registry('db');
        $LANG = JFX::registry('lang');
        $CONFIG = JFX::registry('config');
		$CORE = JFX::registry('JFX_Core');

        //$DB->debug(true);
        //$DB->showErrors(true);
        if($this->parentid == ''){
			throw new exception('Block needs a parent id before it can be saved');
            JFX::addError('Block needs a parent id before it can be saved');
            return false;
        }
        if($this->pageid == ''){
            JFX::addError('Block needs a page id before it can be saved');
            return false;
        }
        if($this->id == ''){
            JFX::addError('Block needs an id before it can be saved');
            return false;
        }

        $numExistingBlocks = $DB->countRows($CONFIG->dbprefix.'blocks', "id = '{$this->id}' AND parent_id = '{$this->parentid}' AND workspace_id = '{$this->workspaceid}'");
        if($numExistingBlocks == 0){
            // first save, insert
            $DB->insert($CONFIG->dbprefix.'blocks', $this->details);
            $CORE->updateContentLang('heading', $this->id, $this->title, '', $this->workspaceid);
        }else if($numExistingBlocks > 0){
            // updating
            $DB->update($CONFIG->dbprefix.'blocks', $this->details, "id = '{$this->id}' AND workspace_id = '{$this->workspaceid}' AND page_id = '{$this->pageid}'");

            $CORE->updateContentLang('heading', $this->id, $this->title, '', $this->workspaceid);
        }

        foreach($this->elements as $k=>$el){
            $el->save();
        }

    }

    public function setRecursiveDetail($colname, $value){
        if(array_key_exists($colname, $this->details)) $this->details[$colname] = $value;
        if($colname == 'parent_id') $this->parentid = $value;
        if($colname == 'workspace_id') $this->workspaceid = $value;
        if($colname == 'module_action') $this->moduleAction = $value;
        if($colname == 'id') $this->id = $value;
        if($colname == 'page_id') $this->pageid = $value;
        foreach($this->elements as $k=>$v){
            if(is_object($v)) $this->elements[$k]->setRecursiveDetail($colname, $value);
        }
    }

    public function copy($newPageid, $newWorkspaceid){
        if($this->pageid != $newPageid || $this->workspaceid != $newWorkspaceid) $this->saved = false;
        $oldWorkspaceid = $this->workspaceid;
        $oldPageid = $this->pageid;
        $oldBlockid = $this->id;
        $this->workspaceid = $newWorkspaceid;
        $this->pageid = $newPageid;
        $this->setDetails('page_id', $newPageid);
        $this->pageid = $newPageid;
        $this->workspaceid = $newWorkspaceid;
        $this->details['workspace_id'] = $newWorkspaceid;
        
        $ids = explode('-', $oldBlockid);
        $this->id = 'jfxpage-'.$newPageid.'-'.$ids[2].'-'.$ids[3];
        $this->details['id'] = $this->id;
        $pids = explode('-', $this->parentid);
        if(count($pids)>2) $this->parentid = 'jfxpage-'.$newPageid.'-'.$pids[2].'-'.$pids[3];
        else $this->parentid = 'jfxpage-'.$newPageid;
        $this->details['parent_id'] = $this->parentid;

        $this->save();
        foreach($this->elements as $k=>$v){
            if(is_object($v)) $this->elements[$k]->copy($newPageid, $newWorkspaceid);
        }
        if(!is_object($this->object)) $this->loadObject();
        $this->object->copyToNewBlock($oldBlockid, $this->id, $oldWorkspaceid, $newWorkspaceid);

    }

	public function setTitle($title){
		$CORE = JFX::registry('JFX_Core', $language='', $workspace='');
		$CORE->updateContentLang('heading', $this->id, $title, $language, $workspace);
	}

    public function setDetails($details){
        if(is_array($details)){
            if(array_key_exists('id', $details)){
                $this->id = $details['id'];
            }
            if(array_key_exists('parent_id', $details)){
                $this->parentid = $details['parent_id'];
                $this->details['parent_id'] = $details['parent_id'];
            }
            if(array_key_exists('page_id', $details)){
                $this->pageid = $details['page_id'];
                $this->setDetails('page_id', $details['page_id']);
            }
            if(array_key_exists('workspace_id', $details)){
                $this->workspaceid = $details['workspace_id'];
                $this->details['workspace_id'] = $details['workspace_id'];
            }
            if(array_key_exists('pageid', $details)){
                $this->pageid = $details['page_id'];
                $this->setDetails('page_id', $details['page_id']);
            }
            if(array_key_exists('module_key', $details)){
                $this->moduleKey = $details['module_key'];
            }
            if(array_key_exists('module_action', $details)){
                $this->moduleAction = $details['module_action'];
            }
            foreach($this->details as $k=>$v){
                if(array_key_exists($k, $details)) $this->details[$k] = $details[$k];
            }
            if(array_key_exists('title', $details)){
                $this->title = $details['title'];
            }
            return true;

        }else if(is_object($details)){
            if(isset($details->id)){
                $this->id = $details->id;
            }
            if(isset($details->parent_id)){
                $this->parentid = $details->parent_id;
                $this->details['parent_id'] = $details->parent_id;
            }
            if(isset($details->page_id)){
                $this->pageid = $details->page_id;
                $this->setDetails('page_id', $details->page_id);
            }
            if(isset($details->workspace_id)){
                $this->workspaceid = $details->workspace_id;
                $this->details['workspace_id'] = $details->workspace_id;
            }
            if(isset($details->module_key)){
                $this->moduleKey = $details->module_key;
            }
            if(isset($details->pageid)){
                $this->pageid = $details->pageid;
                $this->setDetails('page_id', $details->pageid);
            }
            if(isset($details->module_action)){
                $this->moduleAction = $details->module_action;
                $this->details['module_action'] = $details->module_action;
            }
            if(isset($details->title)){
                $this->title = $details->title;
            }
            foreach($this->details as $k=>$v){
                if(array_key_exists($k, $details)) $this->details[$k] = $details->$k;
            }

            return true;
        }else{
            return false;
        }

    }

	public function moveUp(){
		if(!$this->canMoveUp()){
			return false;
		}

		$parentBlock = self::getBlockById($this->details['parent_id'], $this->details['page_id']);

		if(count($parentBlock->elements)>0 && array_key_exists(intval($this->details['sorting']), $parentBlock->elements)){
			$newSorting = $this->details['sorting']-1;
			$parentBlock->elements[$newSorting]->details['sorting'] = $this->details['sorting'];
			$parentBlock->elements[$newSorting]->save();
			$this->details['sorting'] = $newSorting;
			$this->save();
		}
		
	}

	public function moveDown(){
		if(!$this->canMoveDown()){
			return false;
		}

		$parentBlock = self::getBlockById($this->details['parent_id'], $this->details['page_id']);

		if(count($parentBlock->elements)>0 && array_key_exists($this->details['sorting'], $parentBlock->elements)){
			$newSorting = $this->details['sorting']+1;
			$parentBlock->elements[$newSorting]->details['sorting'] = $this->details['sorting'];
			$parentBlock->elements[$newSorting]->save();
			$this->details['sorting'] = $newSorting;
			$this->save();
		}


	}



	public function addModuleBlock($module, $action, $pageid=''){
		$DB = JFX::registry('db');
		$CONFIG = JFX::registry('config');
		if($pageid == '') $pageid = $this->pageid;
		$newBlock = JFX_Block::newModuleBlock($module, $action);
		$newId = JFX_Block::generateBlockId($pageid, $module);
		$parentBlock = JFX_Block::getBlockById($this->parentid, $this->pageid);
		$sorting = $DB->countRows($CONFIG->dbprefix.'blocks', "page_id = '{$this->pageid}' AND parent_id = '{$this->parentid}'");
		$newBlock->setDetails(
			array(
				'id'=>$newId,
				'template_id' => '',
				'parent_id' => $this->id,
				'page_id' => $pageid,
				'sorting' => $sorting
			)
		);
		if($this instanceof JFX_Page){
			$newBlock->setDetails(array('page_parent'=>1));
			$newBlock->setDetails(array('is_droppable'=>1));

		}
		$newBlock->save();
		$this->elements[] = $newBlock;
		$this->save();
	}

	public function addTemplateBlock($templateId, $pageid='', $workspaceid=''){
		$DB = JFX::registry('db');
		$CONFIG = JFX::registry('config');
		$USER = JFX::registry('JFX_User');
		$pageid = ($pageid=='') ? $this->pageid : $pageid;
		$newBlock = self::getBlockById($templateId, $pageid, '');
		$parentBlock = self::getBlockById($this->parentid, $pageid);
		$sorting = $DB->countRows($CONFIG->dbprefix.'blocks', "page_id = '{$this->pageid}' AND parent_id = '{$this->parentid}'");
		$newId = self::generateBlockId($this->pageid, $newBlock->moduleKey);
		if($pageid=='') $pageid = $this->pageid;
		if($workspaceid==''){
			$workspaceid = $USER->workspace;
		}

		$newBlock->setDetails(
			array(
				'id'=>$newId,
				'template_id'=>$templateId,
				'parent_id'=>$this->id,
				'workspace_id' => $workspaceid,
				'page_id'=>$pageid,
				'sorting' => $sorting
			)
		);
		$newBlock->setTitle(self::getTitleById($this->id, $this->pageid, '', $this->workspaceid), '*', '*');
		
		$newBlock->save();
		$this->elements[] = $newBlock;
		$this->save();

		$page = JFX_Block::getBlockById($this->pageid, $this->pageid);

		$hookParams = array(
		    'page' => $page,
		    'block' => $this,
		    'new_block' => $newBlock,
		    'template_id' => $templateId
		);
		JFX::hook('JFX_Block.addTemplateBlock', $hookParams);
				
	}





	public function canMoveUp(){
		$canMove = false;

		$parentBlock = self::getBlockById($this->details['parent_id'], $this->details['page_id']);

		if(count($parentBlock->elements)>0){
			if($parentBlock->elements[0]->details['id']!==$this->id){
				$canMove = true;
			}
		}

		return $canMove;
	}
	public function canMoveDown(){
		$canMove = false;

		$parentBlock = self::getBlockById($this->details['parent_id'], $this->details['page_id']);

		if(count($parentBlock->elements)>0){
			if($parentBlock->elements[count($parentBlock->elements)-1]->details['id']!==$this->id){
				$canMove = true;
			}
		}

		return $canMove;
	}
	public function canInsert(){
		$canInsert = true;
		$SETTINGS = JFX::registry('JFX_Settings');

		if($this->isPage && $SETTINGS->get('template_page_id')==$this->pageid){
			$canInsert = false;
		}

		if(!$this->isPage && $this->details['is_droppable']<=0){
			$canInsert = false;
		}

		return $canInsert;
	}
	public function canDelete(){
		$canDelete = true;
		if(count($this->elements)>0){
			$canDelete = false;
		}
		if(strlen($this->details['template_id'])>0){
			$canDelete = true;
		}

		return $canDelete;
	}

    public function getElements(){
        $els = $this->elements;
        foreach($els as $k=>$v){
            if(isset($v->object)){
                $els[$k]->object->ownerLicense = '';
                $els[$k]->object->publicLicense = '';
            }
            $els[$k]->elements = $els[$k]->getElements();
        }
        return $els;
    }

    public function getDetailsRecursive(){
        $details = $this->getDetails();
        $details['elements'] = array();
        $elements = $this->getElements();
        foreach($elements as $k=>$v){
            $block = new JFX_Block;
            $block->loadById($v->id, $this->details['page_id']);
            $blockEls = $block->getElements();
            if(count($blockEls)>0){
                $details['elements'][$k] = $block->getDetailsRecursive();
            }else{
                $details['elements'][$k] = array_merge($block->getDetails(), array('elements'=>$block->getElements()));
            }
        }
        return $details;
    }

    public function __toJson(){
        // recursive function
		$USER = JFX::registry('JFX_User');
		$THEME = JFX::registry('JFX_Theme');
		$pageid = array_key_exists('page_id', $this->details)
			? $this->details['page_id']
			: preg_replace('/[^0-9]/', '', $this->pageid)
			;
		$this->action_buttons = $THEME->getBlockActionButtons($this->id, $this->pageid);
		$this->title = self::getTitleById($this->id, $this->pageid, '', $USER->workspace);
		if(!$this->isPage){
			$this->content = $this->object->getContent($this->id, $this->pageid);
		}
		if(empty($this->elements)){
			$this->elements = array();
		}
		$allBlocks = $this->elements;
		foreach($allBlocks as $k=>$block){
			$allBlocks[$k] = json_decode($block->__toJson());
		}
		$block = clone $this;
		$block->elements = $allBlocks;

        return json_encode($block);
    }



}